#include "intersection.h"
#include "adaptive_precision.h"
#include <algorithm>
#include <limits>
#include <boost/numeric/interval.hpp>


segment_t::segment_t(double Xa_, double Ya_, double Xb_, double Yb_):Xa(Xa_),Ya(Ya_),Xb(Xb_),Yb(Yb_)
{
}

int interval_turn(double Xa, double Ya, double Xb, double Yb, double Xc, double Yc)
{
	boost::numeric::interval<double> Xa_int(Xa);
	boost::numeric::interval<double> Ya_int(Ya);
	boost::numeric::interval<double> Xb_int(Xb);
	boost::numeric::interval<double> Yb_int(Yb);
	boost::numeric::interval<double> Xc_int(Xc);
	boost::numeric::interval<double> Yc_int(Yc);
	boost::numeric::interval<double> product = Xb_int * Yc_int - Xb_int * Ya_int - Xa_int * Yc_int - Xc_int * Yb_int + Xc_int * Ya_int + Xa_int * Yb_int;
	if (boost::numeric::zero_in(product))
	{
		return adaptive_precision_turn(Xa, Ya, Xb, Yb, Xc, Yc);
	}
	if (product.lower() > 0)
	{
		return 1;
	}
	else
	{
		return -1;
	}
}

int turn(double Xa, double Ya, double Xb, double Yb, double Xc, double Yc)
{
        double imprecision = 4 * std::numeric_limits<double>::epsilon() * 
                (std::abs((Xb - Xa) * (Yc - Ya)) + std::abs((Yb - Ya) * (Xc - Xa)));
		double product = (Xb - Xa) * (Yc -Ya) - (Yb - Ya) * (Xc - Xa);

		if (product > imprecision) return 1;
		if (product < -imprecision) return -1;
		return interval_turn(Xa,Ya,Xb,Yb,Xc,Yc);
}

bool if_intersect(segment_t const& s1, segment_t const& s2)
{
	if ((std::max(s1.Xa,s1.Xb) < std::min(s2.Xa,s2.Xb)) || (std::min(s1.Xa,s1.Xb) > std::max(s2.Xa,s2.Xb)) ||
		 (std::max(s1.Ya,s1.Yb) < std::min(s2.Ya,s2.Yb)) || (std::min(s1.Ya,s1.Yb) > std::max(s2.Ya,s2.Yb)))
	{
		return false;
	}
	else
	{
		return turn(s1.Xa,s1.Ya,s1.Xb,s1.Yb,s2.Xa,s2.Ya) * turn(s1.Xa,s1.Ya,s1.Xb,s1.Yb,s2.Xb,s2.Yb) <= 0 && 
			   turn(s2.Xa,s2.Ya,s2.Xb,s2.Yb,s1.Xa,s1.Ya) * turn(s2.Xa,s2.Ya,s2.Xb,s2.Yb,s1.Xb,s1.Yb) <= 0;
	}
}